<template>
  <div class="JNPF-common-layout">

    <div class="JNPF-common-layout-center">
      <div class="main">
        <!-- 内容区域  每个模块的id要与menu的id一一对应-->
        <section class="content" id="gonglu">
          <div class="header">
            公路运输
          </div>
        </section>
        <section class="content" id="tielu">
          <div class="header">
            铁路运输
          </div>
        </section>
        <section class="content" id="shuilu">
          <div class="header">
            水路运输
          </div>
        </section>
        <section class="content" id="cangchu">
          <div class="header">
            仓储统配
          </div>
        </section>
        <section class="content" id="ceshi">
          <div class="header">
            测试
          </div>
        </section>
        <!-- 侧边栏 -->
        <ul class="sidebar">
          <li v-for="item in menu" :key="item.name" :class="{ active: 1 === item.active }">
            <a href="javascript:;" @click="scrollTo(item)">{{ item.name }}</a>
          </li>
        </ul>

      </div>
    </div>
  </div>

</template>

<script>
export default {
  props: {},
  data() {
    return {
      menu: [
        {
          name: '公路运输',
          id: 'gonglu',
          active: 0, // 用来判断侧边栏的激活状态，为1则代表激活，class的active为true。
        },
        {
          name: '铁路运输',
          id: 'tielu',
          active: 0,
        },
        {
          name: '水路运输',
          id: 'shuilu',
          active: 0,
        },
        {
          name: '仓储统配',
          id: 'cangchu',
          active: 0,
        },
        {
          name: '测试',
          id: 'ceshi',
          active: 0,
        }
      ]
    }
  },
  mounted() {
    //获取每个模块的参数，因为模块在整页渲染完毕后，offsetTop和scrollHeight值已经是确立的，所以在滚动监听之前可以先获取，暂存在menu中。
    this.menu.forEach(item => {
      item.offsetTop = document.getElementById(item.id).offsetTop;
      item.scrollHeight = document.getElementById(item.id).scrollHeight;
    })
    // 监听滚动事件
    document.querySelector('.main').addEventListener('scroll', this.onScroll)
    this.onScroll()
  },
  destroy() {
    console.log('destroy');
    // 必须移除监听器，不然当该vue组件被销毁了，监听器还在就会出错
    document.querySelector('.main').removeEventListener('scroll', this.onScroll)
  },
  methods: {
    // 滚动监听器
    onScroll() {
      // 获取浏览器窗口高度
      let clientHeight = document.querySelector('.JNPF-common-layout-center').innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      // 获取当前文档流的 scrollTop
      let scrollTop = document.querySelector('.main').scrollTop || document.body.scrollTop;
      // 屏幕垂直中线
      let screenMiddle = scrollTop + clientHeight / 2;
      this.menu.forEach(item => {
        //以浏览器窗口垂直中线为准，中线在内容模块的上边界至下边界之间，导航栏都认为在该楼层
        if (screenMiddle - item.offsetTop >= 0 && screenMiddle - item.offsetTop < item.scrollHeight) {
          item.active = 1;
        } else {
          item.active = 0;
        }
      })
    },
    // 跳转到指定索引的元素
    scrollTo(item) {
      // 获取目标的 offsetTop
      // css选择器是从 1 开始计数，我们是从 0 开始，所以要 +1
      const targetOffsetTop = document.getElementById(item.id).offsetTop
      // 获取当前 offsetTop
      let scrollTop = document.querySelector('.main').scrollTop || document.body.scrollTop
      // 定义一次跳 50 个像素，数字越大跳得越快，但是会有掉帧得感觉，步子迈大了会扯到蛋
      const STEP = 700
      // 判断是往下滑还是往上滑
      if (scrollTop > targetOffsetTop) {
        // 往上滑
        smoothUp()
      } else {
        // 往下滑
        smoothDown()
      }
      // 定义往下滑函数
      function smoothDown() {
        // 如果当前 scrollTop 小于 targetOffsetTop 说明视口还没滑到指定位置
        if (scrollTop < targetOffsetTop) {
          // 如果和目标相差距离大于等于 STEP 就跳 STEP
          // 否则直接跳到目标点，目标是为了防止跳过了。
          if (targetOffsetTop - scrollTop >= STEP) {
            scrollTop += STEP
          } else {
            scrollTop = targetOffsetTop
          }
          document.querySelector('.main').scrollTop = scrollTop
          // document.documentElement.scrollTop = scrollTop
          // 关于 requestAnimationFrame 可以自己查一下，在这种场景下，相比 setInterval 性价比更高
          requestAnimationFrame(smoothDown)
        }
      }
      // 定义往上滑函数
      function smoothUp() {
        if (scrollTop > targetOffsetTop) {
          if (scrollTop - targetOffsetTop >= STEP) {
            scrollTop -= STEP
          } else {
            scrollTop = targetOffsetTop
          }
          document.querySelector('.main').scrollTop = scrollTop
          // document.documentElement.scrollTop = scrollTop
          requestAnimationFrame(smoothUp)
        }
      }
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" scoped>
.main {
  padding: 30px;
  padding-right: 240px;
  overflow: auto;
  background: #ffffff;
  .content {
    height: 70vh;
    background: #eee;
    border-radius: 8px;
    margin-bottom: 15px;
  }

  .header {
    padding: 15px;
    font-size: 20px;
    font-weight: 600;
    color: black;
  }
}

.sidebar {
  position: fixed;
  top: 50%;
  right: 50px;
  width: 168px;
  overflow: hidden;
  background-color: #fff;
  border-radius: 8px;
  padding: 0;
  transform: translateY(-50%);
  box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.05), 0px 3px 5px 0px rgba(0, 0, 0, 0.06), 0px 2px 4px -1px rgba(0, 0, 0, 0.04);

  li {
    line-height: 40px;
    text-align: center;
    list-style: none;

    &:not(:last-child) {
      border-bottom: #f5f5f5 solid 1px;
    }

    &.active {
      color: #fff;
      background-color: #ff8000;
    }

    a {
      display: block;
      width: 100%;
      height: 100%;
      color: #333;
      text-decoration: none;
    }
  }
}
</style>
